﻿#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>

//int main()//规避野指针:1.初始化 2. ⼩⼼指针越界 3.指针变量不再使⽤时，及时置NULL4.避免返回局部变量的地址
//{
//	/*int a = 10;//初始化方法1
//	int* p1 = &a;
//
//	int* p2=NULL;//初始化方法2
//	*p2 = 20;//error  NULL值是0，0也是地址，这个地址是⽆法使⽤的
//	if(p!=NULL)//判断*/
//
//	/*
//	 int arr[10] = {1,2,3,4,5,67,7,8,9,10};
//	 int *p = &arr[0];
//	 for(i=0; i<10; i++)
//	 {
//		*(p++) = i;
//	 }
//	 //此时p已经越界了，可以把p置为NULL
//	 p = NULL;
//	                  //下次使⽤的时候，判断p不为NULL的时候再使⽤
//	 p = &arr[0];//重新让p获得地址
//	 if(p != NULL) //判断
//	 {
//	 }*/
//
//	return 0;
//}


//#define NDUBUG//assert失效
//#include<assert.h>
//int main()//断言assert（）⽤于在运⾏时确保程序符合指定条件，如果不符合，就报错终⽌运⾏
//{
//   //assert(p != NULL);//验证变量 p 是否等于 NULL.如果确实不等于 NULL程序继续运⾏.否则就会终⽌运⾏并且给出报错信息提⽰。
//	int a = 10;
//	//int* p = &a;
//	int* p = NULL;
//	assert(p != NULL);
//	*p = 20;
//	printf("%d\n", a);
//	printf("%d\n", *p);
//	return 0;
//}

//#include<string.h>//strlen实现
//int main()
//{
//	char arr[] = "abcdef";
//	int len = strlen(arr);//strlen计算字符串长度(\0之前的字符个数)
//	printf("%d\n", len);
//	return 0;
//}

//#include<assert.h>
//size_t my_strlen(const char *p)//strlen的模拟实现
//{
//	int count = 0;
//	assert(p != NULL);
//	while (*p != '\0')
//	{
//		count++;
//		p++;
//	}
//	return count;
//}
//int main()
//{
//	char ch[] = { "abcdef" };
//	int len = my_strlen(ch);
//	printf("%zd", len);
//	return 0;
//}

//void swap(int *px, int *py)
//{
//	int z = 0;//实参传递给形参的时候，形参会单独创建⼀份临时空间来接收实参，对形参的修改不影响实参。（借助指针）
//	z = *px;
//	*px = *py;
//	*py = z;
//}
//int main()//传址调⽤
//{
//	int a = 10;
//	int b = 20;
//	printf("交换前a=%d,b= %d\n", a, b);
//	swap(&a, &b);
//	printf("交换后a=%d,b= %d\n", a, b);
//	return 0;
//}

// 传值调用
//void swap(int *px, int *py)
//{
//	int z = 0;//实参传递给形参的时候，形参会单独创建⼀份临时空间来接收实参，对形参的修改不影响实参。（借助指针）
//	z = x;
//	x = y;
//	y = z;
//}
//int main()//传址调⽤
//{
//	int a = 10;
//	int b = 20;
//	printf("交换前a=%d,b= %d\n", a, b);
//	swap(&a, &b);
//	printf("交换后a=%d,b= %d\n", a, b);
//	return 0;
//}


//int main()// 数组名的理解
//{
//	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
//	printf("%p\n", arr);
//	printf("%p\n", arr+1);
//	printf("%p\n", &arr[0]);//数组名就是数组⾸元素(第⼀个元素)的地址。
//	printf("%p\n", &arr[0]+1);//&arr[0]+1跳过一个元素
//	
//	//printf("%d\n", sizeof(arr));//sizeof(数组名)，sizeof中单独放数组名，这⾥的数组名表⽰整个数组，计算的是整个数组的⼤⼩，单位是字节
//	
//	printf("%p\n", &arr);  //&数组名，这⾥的数组名表⽰整个数组，取出的是整个数组的地址
//	printf("%p\n", &arr+1);//&arr+1跳过一个数组
//	return 0;
//}


//int main()//指针访问数组
//{
//	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
//	int* p = arr;
//	int sz = sizeof(arr) / sizeof(arr[0]);
//	//输入
//	for (int i = 0; i < sz; i++)
//	{
//		scanf("%d", &arr[i]);
//	}
//	//输入
//	for (int i = 0; i < sz; i++)
//	{
//		scanf("%d", p+i);
//	}
//
//	//输出
//	for (int i = 0; i < sz; i++)
//	{
//		printf("%d ", *p);
//		p++;
//		//printf("%d ", *(p+i));
//		//printf("%d ", p[i]);//arr[i]==*(p+i)==*(arr+i)==p[i]
//	}
//	return 0;
//}


//void test(int arr[])
//{
//	int sz2=sizeof(arr)/ sizeof(arr[0]);
//	printf("%d", sz2);//结果是2
//}
//int main()//⼀维数组传参的本质:传过去的是数组首元素地址，形参的部分可以写成指针形式，也可以写成数组形式，本质都是指针
//{
//	int arr[10] = { 0 };
//	int sz1 = sizeof(arr) / sizeof(arr[0]);
//	printf("%d", sz1);
//	test(arr);
//	return 0;
//}


//void func(int *arr,int sz)//冒泡排序
//{
//	for (int i = 0; i < sz - 1; i++)//sz-1躺
//	{
//		int flag = 1;//假设有序
//		for (int j = 0; j <sz-i-1;j++)//一趟几对比较
//		{
//			if (*(arr+j) > *(arr+j+1))
//			{
//				int temp = *(arr+j);
//				*(arr + j) = *(arr + j+1);
//				*(arr + j + 1) = temp;
//				flag = 0;
//			}
//		}
//		if (flag == 1)
//		{
//			break;
//		}
//	}
//}
//void print(int arr[], int sz)
//{
//	for (int i = 0; i < sz; i++)
//	{
//		printf("%d ", arr[i]);
//	}
//	printf("\n");
//}
//int main()// 冒泡排序
//{
//	int arr[] = { 9,8,7,6,5,4,3,2,1 };//排成升序
//	int sz = sizeof(arr) / sizeof(arr[0]);
//	func(arr,sz);
//	print(arr, sz);
//	return 0;
//}


int main()//二级指针
{
	//int a = 10;
	//int* p = &a;
	//int* *pp = &p;//二级指针变量是用来存放一级指针变量的地址  pp指向的对象是int*
	
	int a = 10;//用法
	int* p = &a;
	int* *pp = &p;
	* *pp = 20;
	printf("%d", 20);
	return 0;
}